package events

import (
	"context"
	"sync"

	"github.com/sirupsen/logrus"

	"BookStack/internal/domain/events"
)

// eventPublisher 事件发布者实现
type eventPublisher struct {
	handlers map[string][]events.EventHandler
	mu       sync.RWMutex
	logger   *logrus.Logger
}

// NewPublisherWithLogger 创建带日志的事件发布者
func NewPublisherWithLogger(logger *logrus.Logger) events.Publisher {
	return &eventPublisher{
		handlers: make(map[string][]events.EventHandler),
		logger:   logger,
	}
}

// Publish 同步发布事件
func (p *eventPublisher) Publish(ctx context.Context, event events.Event) error {
	p.mu.RLock()
	handlers, exists := p.handlers[event.EventType()]
	p.mu.RUnlock()

	if !exists {
		p.logger.WithFields(logrus.Fields{
			"event_type": event.EventType(),
			"event_id":   event.EventID(),
		}).Debug("No handlers registered for event type")
		return nil
	}

	for _, handler := range handlers {
		if err := handler.Handle(ctx, event); err != nil {
			p.logger.WithFields(logrus.Fields{
				"event_type": event.EventType(),
				"event_id":   event.EventID(),
				"error":      err.Error(),
			}).Error("Failed to handle event")
		}
	}

	return nil
}

// AsyncPublish 异步发布事件
func (p *eventPublisher) AsyncPublish(ctx context.Context, event events.Event) {
	go func() {
		// 创建一个新的上下文，避免原始上下文被取消
		newCtx := context.Background()
		if err := p.Publish(newCtx, event); err != nil {
			p.logger.WithFields(logrus.Fields{
				"event_type": event.EventType(),
				"event_id":   event.EventID(),
				"error":      err.Error(),
			}).Error("Failed to async publish event")
		}
	}()
}

// Subscribe 订阅事件
func (p *eventPublisher) Subscribe(eventType string, handler events.EventHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	if _, exists := p.handlers[eventType]; !exists {
		p.handlers[eventType] = []events.EventHandler{}
	}

	p.handlers[eventType] = append(p.handlers[eventType], handler)

	p.logger.WithField("event_type", eventType).Debug("Handler subscribed to event type")
}

// Unsubscribe 取消订阅
func (p *eventPublisher) Unsubscribe(eventType string, handler events.EventHandler) {
	p.mu.Lock()
	defer p.mu.Unlock()

	if handlers, exists := p.handlers[eventType]; exists {
		for i, h := range handlers {
			if h == handler {
				p.handlers[eventType] = append(handlers[:i], handlers[i+1:]...)
				p.logger.WithField("event_type", eventType).Debug("Handler unsubscribed from event type")
				return
			}
		}
	}
}
